﻿using Microsoft.Extensions.Logging;
using RabbitMQ.Client.Events;
using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LeafCore.Components.RabbitMQ
{
    public class RabbitMQListener
    {
        private readonly ILogger<RabbitMQListener> _logger;
        private readonly RabbitMQOptions _options;

        public RabbitMQListener(ILogger<RabbitMQListener> logger, RabbitMQOptions options)
        {
            _logger = logger;
            _options = options;
        }

        /// <summary>
        ///  简单消费者(简单模式)
        /// </summary>
        /// <param name="queueName"></param>
        /// <param name="handler"></param>
        public void SimpleConsumer(string queueName, Action<string> handler)
        {
            var connection = RabbitMQContext.GetConnection(_options.Host, _options.Port, _options.UserName, _options.Password);
            var channel = connection.CreateModel();
            //注：消费者这里有一个创建队列，它本身不需要，是预防消费端程序先执行，没有队列会报错。
            channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);

            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += (model, ea) =>
            {
                //消费者业务处理
                var message = Encoding.UTF8.GetString(ea.Body.ToArray());
                handler(message);
            };
            channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
        }

        /// <summary>
        ///  消费者(工作队列模式)
        /// </summary>
        /// <param name="queueName"></param>
        /// <param name="handler"></param>
        public void WorkConsumer(string queueName, Func<string, bool> handler)
        {
            var connection = RabbitMQContext.GetConnection(_options.Host, _options.Port, _options.UserName, _options.Password);
            var channel = connection.CreateModel();
            //注：消费者这里有一个创建队列，它本身不需要，是预防消费端程序先执行，没有队列会报错。
            channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: false);

            var consumer = new EventingBasicConsumer(channel);
            //prefetchSize：每条消息大小，一般设为0，表示不限制，
            //prefetchCount：作用限流，告诉RabbitMQ不要同时给一个消费者推送多于N个消息，消费者会把N条消息缓存到本地一条条消费，如果不设，RabbitMQ会尽可能快的把消息推到客户端，导致客户端内存升高。设置合理可以不用频繁从RabbitMQ 获取能提升消费速度和性能，设的太多的话则会增大本地内存，需要根据机器性能合理设置，官方建议设为30
            channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
            consumer.Received += (model, ea) =>
            {
                //消费者业务处理
                var message = Encoding.UTF8.GetString(ea.Body.ToArray());
                var result = handler(message);
                if (result)
                {
                    // 消息的标识，false只确认当前一个消息收到，true确认所有consumer获得的消息（成功消费，消息从队列中删除 ）
                    channel.BasicAck(ea.DeliveryTag, false);
                }
            };
            //这些限流设置针对消费者autoAck：false时才有效，如果是自动Ack的，限流不生效。
            channel.BasicConsume(queueName, autoAck: false, consumer);
        }
    }
}
